package org.tony.spider.novel.core;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.Node;
import org.jsoup.select.Elements;
import org.tony.common.http.Browser;
import org.tony.common.http.URLUtils;
import org.tony.spider.core.util.SpiderHelper;
import org.tony.spider.novel.entries.Book;
import org.tony.spider.novel.entries.BookStatus;
import org.tony.spider.novel.entries.Chapter;
import org.tony.spider.novel.entries.NovelQueue;
import org.tony.spider.novel.utils.BookConfigUtil;

public abstract class BookCatalogueQuery
{
  protected Book    book;
  protected Browser browser;

  //  protected Integer         threadCount;
  //  protected ExecutorService threadPools;

  public BookCatalogueQuery(Book book)
  {
    this.book = book;
    this.browser = SpiderHelper.openBrowser();
    //    this.threadCount = 10;
    //    this.threadPools = Executors.newFixedThreadPool(threadCount);

    //initial other special configuration
    this.initalOtherSpecConfigs();
  }

  /**
   * initial the special configurations
   * for example:
   *  when we parse the www.epzw.com web-site ,we must use the GBK encoding for the content parsing,otherwise
   *  the return content will contain messy code.
   */
  protected abstract void initalOtherSpecConfigs();

  /**
   * do the query
   */
  public void query()
  {
    Elements catalogues = null;
    String content = browser.open(book.getUrl());
    Document doc = Jsoup.parse(content);
    String[] selects = book.getFromSite().getCatalogueSelectLabels();
    if (selects == null || selects.length == 0)
    {
      throw new RuntimeException("Parsing Error: The selected labels of  book's catalogue must be set");
    }
    catalogues = doc.select(selects[0]);
    for (int i = 1; i < selects.length; i++)
    {
      catalogues = catalogues.select(selects[i]);
    }
    handlerCatalogues(catalogues);
  }

  protected void handlerCatalogues(Elements catalogues)
  {
    boolean flag = false;
    Integer counter = 0;
    Queue<Chapter> notFetchedChapters = new LinkedBlockingQueue<Chapter>();
    if (catalogues != null)
    {
      Iterator<Element> iterForCatalogue = catalogues.iterator();
      while (iterForCatalogue.hasNext())
      {

        Element catalogue = iterForCatalogue.next();
        if (catalogue.childNodes().size() > 0)
        {
          Node chapterNode = catalogue.childNode(0);
          String url = catalogue.attr("href");
          String title = chapterNode.attr("text");

          if (title.matches(book.getFromSite().getChapterIdentifier()))
          {
            counter++;
            if (book.getStatus() == BookStatus.loading && !flag)
            {
              if (title.matches(book.getLastUpdated()))
              {
                flag = true;
                continue;
              }
              else
              {
                continue;
              }
            }
            boolean isVip = true;
            Chapter chapter = new Chapter();
            if (!url.contains(book.getFromSite().getVipTags()))
            {
              isVip = false;
              url = URLUtils.getUrl(book.getUrl(), url);
              chapter.setUrl(url);
            }
            chapter.setIsVipChapters(isVip);
            chapter.setBook(book);
            chapter.setOriginalTitle(title);
            chapter.setTitle(getCustomizedTitle(title, counter));
            notFetchedChapters.add(chapter);
          }
        }
      }
      if (!notFetchedChapters.isEmpty())
      {
        // append this chapters to NovelQueue so that other work thread can read it.
        NovelQueue.getInstance().append(book.getName(), notFetchedChapters);

        //get the last-updated chapter and modified the books information
        Map<String, String> props = new HashMap<String, String>();
        Object[] c = notFetchedChapters.toArray();
        props.put("last-update", ((Chapter)c[c.length - 1]).getOriginalTitle());
        props.put("status", BookStatus.loading.name());
        BookConfigUtil.getInstance().update(book.getId(), props);
      }
    }
    else
    {
      throw new RuntimeException(
          "Parse Error: There is no result for parsing this web site.Please checking your input"
              + " isn't correct. ");
    }
  }

  /**
   * we used this method to replace this title for display 
   * 
   * @param orignal
   * @param currentCounter
   * @return
   */
  protected String getCustomizedTitle(String orignal, Integer currentCounter)
  {
    return orignal.replaceAll("\u7B2C.+\u7AE0", String.format("\u7B2C%d\u7AE0", currentCounter));
  }
}
